package ilender.controller;

import java.io.*;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

import lombok.*;

import com.google.gson.*;
import org.apache.commons.lang3.StringUtils;

import com.google.common.io.BaseEncoding;

import com.google.common.collect.*;

import ilender.annotations.*;
import ilender.dispatching.ControllerTools;
import ilender.mappers.*;
import ilender.models.*;
import ilender.util.*;
import ilender.facebook.*;
import ilender.exceptions.*;

/**
 * @see Controller
 */
@Controller("items")
public class ItemsController{
	/**
	 * Register an item.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         category_id:(the id of the category),
	 *         name:(the name of the new item),
	 *         description:(the description of the new item),
	 *         tags:(a comma\space separated list of tags for the new item)
	 *     }
	 * }
	 * </pre>
	 * @throws IOException
	 */
	public static JsonElement add(JsonObject request,ControllerTools tools) throws IOException{
		JsonObject formData=request.getAsJsonObject("form_data");
		MItem newItem=new MItem();
		newItem.setCategory_id(Long.valueOf(formData.get("category_id").getAsString()));
		newItem.setName(formData.get("name").getAsString());
		newItem.setDescription(formData.get("description").getAsString());
		newItem.setFacebook_user_id(tools.fbUser.id);
		newItem.setTags(
				Lists.newArrayList(StringUtils.split(formData.get("tags").getAsString()," ,"))
				);

		if(!formData.get("imagefile-data").isJsonNull()){
			// grab the encoded data of the image
			String imageFileEncoded = formData.get("imagefile-data").getAsString();

			String[] imageFileEncodedParts=imageFileEncoded.split(";");

			// convert from BASE64
			byte[] decodedBytes=BaseEncoding.base64().decode(imageFileEncodedParts[1].split(",",2)[1]);

			//Convert image type to PNG
			BufferedImage image=ImageIO.read(new ByteArrayInputStream(decodedBytes));
			ByteArrayOutputStream os=new ByteArrayOutputStream();
			ImageIO.write(image,"png",os);
			byte[] pngImageData=os.toByteArray();

			val imagesMapper=tools.session.getMapper(ImagesMapper.class);
			long imageId = imagesMapper.insertImage(pngImageData);
			newItem.setImage_id(imageId);
		}

		val itemsMapper=tools.session.getMapper(ItemsMapper.class);
		newItem.save(itemsMapper);

		//Autooffer the requests the user has marked
		if(formData.has("offer_requests")){
			JsonArray offerRequests=formData.getAsJsonArray("offer_requests");
			String result="";
			RequestsMapper requestsMapper=tools.session.getMapper(RequestsMapper.class);
			for(val entry:offerRequests){
				MRequest req=requestsMapper.find(entry.getAsNumber().longValue());
				OffersController.registerOffer(req,newItem,tools);
			}
		}


		//Post on wall
		if(formData.has("post_on_wall")){
			tools.fbUser.postTo(FBPostType.FEED)
				.setMessage(String.format("I offer %s, borrow it in Rebay!",newItem.getName()))
				.setLink(newItem)
				.post();
		}

		//TODO: make it return nothing.
		return JsonTools.makeObject(
				"update",JsonTools.makeArray(
					JsonTools.makeObject("target","#borrowing-panel [contains=cardlets]",
						"ejs","layout/cardlet_list",
						"items",fetchCardlets(tools,""))));
	}

	/**
	 * Search for items.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         search_string:(the search string)
	 *     }
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *     entries:[
	 *         (item cardlet),
	 *         ...
	 *     ]
	 * }
	 * </pre>
	 */
	public static JsonElement search(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		String searchString=formData.get("search_string").getAsString();
		val itemsMapper=tools.session.getMapper(ItemsMapper.class);
		return JsonTools.makeObject(
				"entries",fetchCardlets(tools,searchString));
	}

	/**
	 * Get items suggestions to display for a new request.
	 *
	 * @param request <pre>
	 * {
	 *     form_data:{
	 *         title:(title to search with),
	 *         tags:(tags to search with)
	 *     },
	 *     ignore_item:(id of single item to not show)
	 * }
	 * </pre>
	 * @return <pre>
	 * {
	 *     entries:[
	 *         (item cardlet),
	 *         ...
	 *     ]
	 * }
	 */
	public static JsonElement suggestForNewRequest(JsonObject request,ControllerTools tools){
		JsonObject formData=request.getAsJsonObject("form_data");
		String searchString=String.format("%s %s",
				formData.get("title").getAsString(),
				formData.get("tags").getAsString().replace(","," "));
		JsonObject result=JsonTools.makeObject(
				"entries",fetchCardlets(tools,searchString,4)
				);
		if(request.has("ignore_item")){
			result.add("entries",JsonTools.duplicateArrayWhileIgnoreing(
						result.get("entries").getAsJsonArray(),
						"id",request.get("ignore_item").getAsJsonPrimitive()));
		}
		return result;
	}

	/**
	 * Get all items belonging to the current user.
	 *
	 * @return <pre>
	 * {
	 *     entries:[
	 *         (item cardlet),
	 *         ...
	 *     ]
	 * }
	 */
	public static JsonElement mine(JsonObject request,ControllerTools tools){
		val itemsMapper=tools.session.getMapper(ItemsMapper.class);
		return JsonTools.makeObject(
				"entries",JsonTools.addToEach(JsonTools.addToEach(
						tools.gson.toJsonTree(itemsMapper.userItems(tools.mUser.getId(),0)).getAsJsonArray(),
						"ejs","items/item_cardlet"),
					"unrequestable",true));
	}

	/**
	 * Get all items requested by the current user.
	 *
	 * @return <pre>
	 * {
	 *     entries:[
	 *         (item cardlet),
	 *         ...
	 *     ]
	 * }
	 */
	public static JsonElement thoseIRequested(JsonObject request,ControllerTools tools){
		val itemsMapper=tools.session.getMapper(ItemsMapper.class);
		return JsonTools.makeObject(
				"entries",JsonTools.addToEach(JsonTools.addToEach(
						tools.gson.toJsonTree(itemsMapper.userRequestedItems(tools.mUser.getId(),0)).getAsJsonArray(),
						"ejs","items/item_cardlet"),
					"unrequestable",true));
	}

	/**
	 * Return a list of cardlets.
	 *
	 * @param tools The ControllerTools used for the request.
	 * @param searchString The search string.
	 * @param limit The limit on the search results.
	 * @return A JSON array containing cardlets.
	 */
	public static JsonArray fetchCardlets(ControllerTools tools,String searchString,long limit){
		val itemsMapper=tools.session.getMapper(ItemsMapper.class);
		val offersMapper=tools.session.getMapper(OffersMapper.class);
		val suggestionsMapper=tools.session.getMapper(SuggestionsMapper.class);
		val result=JsonTools.addToEach(
				tools.gson.toJsonTree(itemsMapper.searchItems(searchString,tools.mUser.getId(),limit)).getAsJsonArray(),
				"ejs","items/item_cardlet");
		val idsOfItemsAlreadyRequested=offersMapper.idsOfItemsRequestedBy(tools.fbUser.id);
		val idsOfItemsAlreadySuggested=suggestionsMapper.idsOfItemsSuggestedToUser(tools.fbUser.id);
		val resultFiltered=new JsonArray();
		for(val entry:result){
			val entryObject=entry.getAsJsonObject();
			if(tools.fbUser.id==entryObject.getAsJsonObject("facebook_user").get("id").getAsLong())
				continue;
			//entryObject.addProperty("requested_by_this_user",
					//idsOfItemsAlreadyRequested.contains(Long.valueOf(entryObject.get("id").getAsString())));
			long itemId=Long.valueOf(entryObject.get("id").getAsString());
			if(idsOfItemsAlreadyRequested.contains(itemId))
				continue;
			if(idsOfItemsAlreadySuggested.contains(itemId))
				continue;
			resultFiltered.add(entry);
		}
		return resultFiltered;
	}
	public static JsonArray fetchCardlets(ControllerTools tools,String searchString){
		return fetchCardlets(tools,searchString,0);
	}

	/**
	 * Return a cardlet for a single item.

	 * @param tools The ControllerTools used for the request.
	 * @param id The id of the item.
	 * @return A JSON serialization of the item's cardlet.
	 */
	public static JsonObject fetchSingleCardlet(ControllerTools tools,long id){
		val itemsMapper=tools.session.getMapper(ItemsMapper.class);
		val result=tools.gson.toJsonTree(itemsMapper.find(id)).getAsJsonObject();
		result.addProperty("ejs","items/item_cardlet");
		return result;
	}
}
